﻿#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

//数组与指针笔试题

//?维数组
//int main()
//{
//	int a[] = { 1,2,3,4 };
//	printf("%d\n", sizeof(a));//16
//	//数组名a单独放在sizeof内，a表示整个数组，计算的是整个数组的大小，单位是字节
//
//	printf("%d\n", sizeof(a + 0)); //此处的a表示数组首元素地址，a+0还是首元素地址不变
//	//sizeof计算的是首元素地址的大小————4/8
//
//	printf("%d\n", sizeof(*a));// 4
//	//a表示数组首元素地址，*a得到1，int类型的内存大小为4字节
//
//	printf("%d\n", sizeof(a + 1));// 4/8
//	//a表示首元素地址，a+1表示第二个元素——2，int类型的变量的内存大小为4
//
//	printf("%d\n", sizeof(a[1]));// 4
//	//第二个元素内存大小
//
//	printf("%d\n", sizeof(&a));
//	//&a表示整个数组的地址，但只要是地址，就是4/8的内存空间
//
//	printf("%d\n", sizeof(*&a));// 16
//	//*&a得到的是整个数组
//
//	printf("%d\n", sizeof(&a + 1));// 4/8
//	//&a+1得到的是下一个4/8个内存空间后的数组地址，同样是4/8的内存空间
//
//	printf("%d\n", sizeof(&a[0]));// 4/8
//	//&a[0]指的是第一个元素，是1，其内存空间的大小是4/8
//
//	printf("%d\n", sizeof(&a[0] + 1));// 4/8
//	//&a[0]指的是第一个元素，+1得到的是1+1=2，内存空间是4/8
//
//
//	return 0;
//}


//字符数组——代码1
//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };//该数组内无\0
//	printf("%d\n", sizeof(arr));// 6
//
//	printf("%d\n", sizeof(arr + 0));// 4/8
//
//	printf("%d\n", sizeof(*arr));// 1
//
//	printf("%d\n", sizeof(arr[1]));// 1
//
//	printf("%d\n", sizeof(&arr));// 4/8
//
//	printf("%d\n", sizeof(&arr + 1));// 4/8
//
//	printf("%d\n", sizeof(&arr[0] + 1));// 4/8
//
//	return 0;
//}

//字符数组——代码2
//int main()
//{
//	char arr[] = { 'a','b','c','d','e','f' };//无\0
//	printf("%d\n", strlen(arr));//从首元素开始数，但由于无\0，所以结果随机
//
//	printf("%d\n", strlen(arr + 0));//随机
//
//	printf("%d\n", strlen(*arr));//arr是数组名，表示首元素地址
//	//*arr是首元素————'a' ——ASCLL码值————97，传递给strlen后，strlen将其当做地址，去访问内存、
//	//err--程序崩溃
//
//	printf("%d\n", strlen(arr[1]));//程序崩溃
//
//	printf("%d\n", strlen(&arr));//随机值
//
//	printf("%d\n", strlen(&arr + 1));//随机值
//
//	printf("%d\n", strlen(&arr[0] + 1));//随机值
//
//	return 0;
//}


//字符数组——代码3
//int main()
//{
//	char arr[] = "abcdef";//字符串，在f后有一个\0
//
//	printf("%d\n", sizeof(arr));// 7
//
//	printf("%d\n", sizeof(arr + 0));// 4/8
//
//	printf("%d\n", sizeof(*arr));// 1
//
//	printf("%d\n", sizeof(arr[1]));// 1
//
//	printf("%d\n", sizeof(&arr));// 4/8
//
//	printf("%d\n", sizeof(&arr + 1));// 4/8
//
//	printf("%d\n", sizeof(&arr[0] + 1));// 4/8
//
//	return 0;
//}


//字符数组——代码4
//int main()
//{
//	char arr[] = "abcdef";//字符串，在f后有一个\0
//
//	printf("%zd\n", strlen(arr));// 6
//
//	printf("%zd\n", strlen(arr + 0));// 6
//
//	printf("%zd\n", strlen(*arr));// 传递的是字符a，程序崩溃
//
//	printf("%zd\n", strlen(arr[1]));// 崩溃
//
//	printf("%zd\n", strlen(&arr));// 6  &arr是数组的地址，它和数组首元素的地址指向一个位置，那么strlen也是从第一个元素开始向后访问的
//
//	printf("%zd\n", strlen(&arr + 1));// 随机值 
//
//	printf("%zd\n", strlen(&arr[0] + 1));// 5
//
//	return 0;
//}


//字符数组——代码5
//int main()
//{
//	char* p = "abcdef";//此处存放的是字符串内第一个字符的地址
//
//	printf("%zd\n", sizeof(p));//p是指针变量，其中存的是a的地址，大小是 4/8
//
//	printf("%zd\n", sizeof(p + 1));//求的是b的地址，大小是 4/8
//
//	printf("%zd\n", sizeof(*p));//*p得到的是字符a，一个字符的内存大小是 1
//
//	printf("%zd\n", sizeof(p[0]));//得到的是a的地址，大小是 1
//
//	printf("%zd\n", sizeof(&p));//&p得到的是指针变量p的地址，大小是 4/8
//
//	printf("%zd\n", sizeof(&p + 1));//&p得到的是p的地址，+1后得到的是地址大小是 4/8
//
//	printf("%zd\n", sizeof(&p[0] + 1));//&p[0]得到的是a的地址，+1后，得到的是b的地址，大小是 4/8
//
//	return 0;
//}


//字符数组——代码6
//int main()
//{
//	char* p = "abcdef";//此处存放的是字符串内第一个字符的地址
//
//	printf("%zd\n", strlen(p));//p中存放的是a的地址，结果是 6
//
//	printf("%zd\n", strlen(p + 1));//p+1得到的是b的地址，结果是 5
//
//	printf("%zd\n", strlen(*p));//*p得到的是字符a，非法访问，程序崩溃
//
//	printf("%zd\n", strlen(p[0]));//p[0]得到的是字符a，非法访问，程序崩溃
//
//	printf("%zd\n", strlen(&p));//&p得到的是指针变量p的地址，结果是 随机值
//
//	printf("%zd\n", strlen(&p + 1));//&p得到的是p的地址，+1后，结果是 随机值
//
//	printf("%zd\n", strlen(&p[0] + 1));//p[0]得到的是a，&p[0]得到a的地址，+1后得到b的地址，结果是 5
//
//	return 0;
//}



//二维数组
//int main()
//{
//	int a[3][4] = { 0 };//初始化了一个三行四列的二维数组
//
//	printf("%zd\n", sizeof(a));//a单独存在于sizeof之中，代表整个数组，由于数组类型是int，所以结果是 48
//
//	printf("%zd\n", sizeof(a[0][0]));//a[0][0]得到的是第一行第一列的元素，结果是 4
//
//	printf("%zd\n", sizeof(a[0]));//a[0]作为第一行的数组名，单独放在sizeof之内，计算的是数组大小，故结果是 16
//
//	printf("%zd\n", sizeof(a[0] + 1));// 4/8
//	//a[0]是第一行数组名，但没有单独放在sizeof中，表示第一行首元素地址，+1后得到第一行第二个元素地址，结果是 4/8
//
//	printf("%zd\n", sizeof(*(a[0] + 1)));//
//	//a[0]是表示第一行首元素地址，+1后表示第二个元素地址，*后得到第一行第二个元素，结果是 4
//	
//	printf("%zd\n", sizeof(a + 1));
//	//a表示二维数组的首元素地址，即第一行的元素地址，+1后得到第二行元素的地址，结果是 4/8
//
//	printf("%zd\n", sizeof(*(a + 1)));
//	//a+1——a[1],代表的是第二行，*后，得到第二行4个元素，由于是整型数组，故结果是 4*4=16
//
//	printf("%zd\n", sizeof(&a[0] + 1));
//	//a[0]是数组名，此处&，得到的是第一行的地址，+1后得到第二行一维数组的地址，结果是 4/8
//
//	printf("%zd\n", sizeof(*(&a[0] + 1)));
//	//&a[0]得到的是第一行一维数组的地址，+1后得到第二行的一维数组的地址，*后得到第二行的四个元素，结果是 4*4=16
//
//	printf("%zd\n", sizeof(*a));
//	//a是二维数组名，但未单独存在，表示第一行的地址，解引用后，得到第一行的4个元素，结果是 16
//
//	printf("%zd\n", sizeof(a[3]));
//	//a[3]是数组名，此处表示第四行，结果是 4*4=16
//
//	return 0;
//}


//指针运算笔试题

//  1
//int main()
//{	
//	int a[5] = { 1, 2, 3, 4, 5 };//初始化一个整型数组
//	int* ptr = (int*)(&a + 1);//将一个地址前进一步（20个字节）强制类型转换为整型指针，存入整型指针=ptr
//	printf("%d,%d", *(a + 1), *(ptr - 1));
//	//a是首元素地址，+1后得到2的地址，*后得到整型 2
//	//ptr-1令ptr回退一步（4个字节），指向5的地址，*后得到整型 5
//	//结果是 2 5
//
//	return 0;
//}


//  2
//在X86环境下 
//假设结构体的⼤⼩是20个字节 
//程序输出的结果是啥？ 

//初始化一个结构体指针
//struct Test
//{
//	int Num;
//	char* pcName;
//	short sDate;
//	char cha[2];
//	short sBa[4];
//}*p = (struct Test*)0x100000;
//
//int main()
//{
//	printf("%p\n", p + 0x1);//  0x100020
//	//指针+1，跳过类型的内存大小，即+20
//
//	printf("%p\n", (unsigned long)p + 0x1);//  0x100001
//	//整数+1，正常相加即可，即+1
//
//	printf("%p\n", (unsigned int*)p + 0x1);//  0x100004
//	//整型指针+1，跳过一个整型内存大小，即+4
//
//	return 0;
//}


//  3
//int main()
//{
//	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
//	// 由于大括号内用小括号区分行列，没有语法意义，实质上是运用逗号表达式，运算结果是最后一个表达式，故实际上数组中存放的是 1,3,5,0,0,0
//
//	int* p;
//
//	p = a[0];//p中存的是第一行一维数组的地址
//
//	printf("%d", p[0]);//p中存放的是第一行的地址，后加[0]代表取出第一个元素，即 1
//
//	return 0;
//}



//  4
//假设环境是x86环境，程序输出的结果是啥？ 

//int main()
//{
//	int a[5][5];
//
//	int(*p)[4];//p是数组指针，指向4个整型指针
//
//	p = a;//p中存放的地址改为数组a的首元素，即第一行的5个元素的地址
//
//	printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
//	//p[4][2]实际上就是p[4]+2或*（*（p+4）+2）
//
//	return 0;
//}



//  5

//int main()
//{
//	int aa[2][5] = { 1, 2, 3, 4, 5,  6, 7, 8, 9, 10 };
//	int* ptr1 = (int*)(&aa + 1);
//	int* ptr2 = (int*)(*(aa + 1));
//	printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
//	return 0;
//}



//  6

//int main()
//{
//	char* a[] = { "work","at","alibaba" };//由于a是字符类型的指针，所以数组中存放的应该是'w','a','a'
//	char** pa = a;//存入w的地址
//	pa++;//存放的地址改变为a的地址
//	printf("%s\n", *pa);//pa存放的是指针变量a的地址，a中存的是w的地址，*pa得到的就是a中存放的地址，即字符a的地址，打印at
//	return 0;
//}



//  7

//int main()
//{
//	char* c[] = { "ENTER","NEW","POINT","FIRST" };//存放的其实是E,N,P,F的地址
//
//	char** cp[] = { c + 3,    c + 2,     c + 1,  c };//存放的是 F,P,N,E
//	//              c+3的地址  c+2的地址  c+1的地址    c中存放的是首元素的地址
//
//	char*** cpp = cp;
//	//存放的是 c+3的地址-->F
//
//	printf("%s\n", **++cpp);
//	//c+3的地址++ -> c+2的地址, *->c+2，*->P的地址    POINT
//
//	printf("%s\n", *-- * ++cpp + 3);
//	//cpp已经++过，值为c+2的地址，++ ->c+1的地址，* -> c+1的地址，*->c+1，-- -> c+,*->E的地址，+3 -> \0,打印  ER
//
//	printf("%s\n", *cpp[-2] + 3);//*cpp[-2]+3 --> *(*(cpp-2))+3
//	//cpp的值是 c+1的地址，-2 -> c+3的地址，* -> c+3,* -> F的地址，+3 -> S的地址，打印  ST 
//
//	printf("%s\n", cpp[-1][-1] + 1);//cpp[-1][-1]+1 --> *(*(cpp-1)-1)+1
//	//cpp的值是 c+1的地址，-1 -> c+2的地址，*->c+2，-1 -> c+1，*->N的地址，+1 -> E的地址，打印  EW
//
//	return 0;
//}
